﻿using Blm.Utils.Extensions;
using Blm.Utils.Utility;
using Blm.VisionCloud.FrameWork.Cached;
using Blm.VisionCloud.FrameWork.VerifyCode;
using Language.Resource;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml.Linq;
using VisionCloud.Core.Model.Ms;
using VisionCloud.Core.Model.Sys;
using VisionCloud.Domain.Common;
using VisionCloud.Domain.DtoModel.Ms;
using VisionCloud.Domain.DtoModel.Sys;
using VisionCloud.Domain.Extension;
using VisionCloud.Domain.Repository.Implement.Sys;
using VisionCloud.Domain.Repository.Interface.Ms;
using VisionCloud.Domain.Repository.Interface.Sys;
using VisionCloud.Domain.UnitOfWork;
using VisionCloud.Service.Ms;
using VisionCloud.Utility;
using VisionCloud.Utility.Extensions;
using VisionCloud.Utility.Option;
using VisionCloud.Utility.Redis;
using VisionCloud.Utility.Security;
using static VisionCloud.Core.Model.Sys.SysUser;
using AjaxCode = VisionCloud.Domain.Common.AjaxCode;

namespace VisionCloud.Service.Sys
{
    public class UserService
    {
        /// <summary>
        /// 默认初始化密码
        /// </summary>
        private const string InitPwd = "Abc@123456";

        /// <summary>
        /// 禁止编辑、删除的用户
        /// </summary>
        private const string ForbidUserCode = "admin";

        /// <summary>
        /// 云端地址
        /// </summary>
        private static readonly string WebUrl = ConfigHelper.GetValue<string>("WebUrl");

        /// <summary>
        /// 验证码有效时间
        /// </summary>
        private static readonly int verifyCodeMinute = ConfigHelper.GetValue<int>("VerifyCodeMinute");

        /// <summary>
        /// 多语言资源类
        /// </summary>
        public IStringLocalizer<ServiceResource> ServiceLocalizer { get; set; }

        public IUnitOfWork UnitOfWork { get; set; }

        public IMsProjectRepository IMsProjectRepository { get; set; }

        public ISysUserRepository SysUserRepository { get; set; }

        public ISysRoleRepository SysRoleRepository { get; set; }

        public ISysUserRoleRepository SysUserRoleRepository { get; set; }

        public ISysOrgUserRepository SysOrgUserRepository { get; set; }

        public ILogRepository LogRepository { get; set; }

        public ISysDeviceUserRepository SysDeviceUserRepository { get; set; }

        public ISysDeviceRepository SysDeviceRepository { get; set; }

        public IMsUserToUserRepository MsUserToUserRepository { get; set; }

        public ISysUserProjectRepository SysUserProjectRepository { get; set; }

        public IMsUserToProjectRepository MsUserToProjectRepository { get; set; }

        public CrossEmailService crossEmailService { get; set; }

        public SmsService smsService { get; set; }

        public StatisService statisService { get; set; }

        public ProjectService ProjectService { get; set; }

        public SysOrgService SysOrgService { get; set; }

        public SysDeviceService sysDeviceService { get; set; }

        public UserToProjectMessageService UserToProjectMessageService { get; set; }

        public ILogger<UserService> logger { get; set; }

        private readonly ICached cached;

        private readonly IVerifyCode verifyCode;

        private UploadFileOptions uploadFileOptions;

        /// <summary>
        /// 24小时内允许获取验证码的次数
        /// </summary>
        private static readonly int maxNumPerAccount = 10;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="option"></param>
        /// <param name="cached"></param>
        /// <param name="verifyCode"></param>
        public UserService(IOptionsMonitor<UploadFileOptions> option, ICached cached, IVerifyCode verifyCode)
        {
            uploadFileOptions = option.CurrentValue;
            this.cached = cached;
            this.verifyCode = verifyCode;
        }

        #region 缓存配置

        private OperatorInfo _tokenModel => OperatorProvider.Get();

        private static string _cacheKeyPre = "UserServiceSysUserCondition";

        /// <summary>
        /// 管理员编辑用户
        /// </summary>
        /// <param name="model"></param>
        /// <param name="opeId"></param>
        /// <returns></returns>
        public async Task UpdateUser(SysUserDto model, Guid opeId)
        {
            if (model.UserId == Guid.Empty)
            {
                throw new OperationException(ServiceLocalizer["YB0016"].Value);
            }

            CheckData(model);
            CheckRight(model);
            #region 用户角色
            if (model.RoleList.Count > 0)
            {
                model.RoleList = model.RoleList.Where(p => p != Guid.Empty).Distinct().ToList();
            }

            await UpdateUserTrans(model, opeId);

            if (model.Status == EnumUserStatus.禁用)
            {
                cached.RemoveByRegex(model.Code);
                cached.RemoveByRegex(model.Email);
                cached.RemoveByRegex(model.PhoneNumber);
            }

            #endregion 用户角色

            cached.RemoveByRegex(_cacheKeyPre);
        }

        /// <summary>
        /// 事务更新用户信息
        /// 1.基本信息
        /// 2.用户角色
        /// 3.测量机器人用户项目
        /// 4.框架平台用户的机器类型
        /// </summary>
        /// <param name="model"></param>
        /// <param name="opeId"></param>
        /// <returns></returns>
        private async Task UpdateUserTrans(SysUserDto model, Guid opeId)
        {
            var oldUserProjects = await MsUserToProjectRepository.GetAll().Where(t => t.YunUserGuid == model.UserId).ToListAsync();
            var newProjectIDs = model.ProjectIds.ToArray();
            bool isCanSend = false;
            List<MsProject> allProject = new List<MsProject>();
            await UnitOfWork.OpenTrans(async (save) =>
           {
               #region 基本信息

               SysUserRepository.Update(t => t.YunUserGuid == model.UserId,
                  d =>
                  {
                      d.AccountNumber = model.AccountNumber;
                      d.Name = model.Name;
                      d.Gender = (SysUser.EnumUserGender?)model.Gender;
                      d.Department = model.Department;
                      d.PhoneNumber = model.PhoneNumber;
                      d.Position = model.Position;
                      d.Email = model.Email;
                      d.LastUpdatedBy = opeId;
                      d.LastUpdatedDate = DateTime.Now;
                      d.AvatarId = model.AvatarId;
                      d.RoleNameList = model.RoleNameList.ToJsonStr();
                      d.Status = model.Status;
                      d.SysOrgId = _tokenModel.OrgId;
                      d.CompanyNo = _tokenModel.OrgCode;
                      d.Company = _tokenModel.Company;
                  });
               #endregion 基本信息

               #region 用户角色
               if (model.RoleList.Count > 0)
               {
                   List<SysUserRole> oldList = new List<SysUserRole>();
                   var oldUserRoles = await GetUserRole(model);
                   foreach (var role in oldUserRoles)
                   {
                       oldList.Add(new SysUserRole() { UserRoleId = role.UserRoleId, UserId = role.UserId, RoleId = role.RoleId });
                   }

                   List<SysUserRole> newList = await GetUserNewRoleAsync(model, opeId);
                   if (oldList != null && oldList.Count > 0)
                   {
                       //清除人员角色数据
                       SysUserRoleRepository.RemoveRange(oldList, true);
                       await save();
                   }

                   //保存新的人员角色数据
                   SysUserRoleRepository.AddRange(newList);
                   await save();
               }
               #endregion 用户角色

               #region 用户组织
               var orgUsers = await SysOrgUserRepository.GetAll().Where(t => t.SysUserId == model.UserId).ToListAsync();
               if (orgUsers.IsNotEmpty())
               {
                   orgUsers.ForEach(t => SysOrgUserRepository.Remove(t, true));
               }

               if (model.SysOrgIds.IsNotEmpty())
               {
                   model.SysOrgIds.ForEach(t => SysOrgUserRepository.Add(new SysOrgUser { SysUserId = model.UserId, SysOrgId = t.ToGuid() }));
               }
               #endregion 用户组织

               #region 用户项目
               var roleNameList = OperatorProvider.Get().RoleNameList;
               if (roleNameList.IndexOf("公司管理员") > -1 || roleNameList.IndexOf("测量管理员") > -1)
               {
                   if (oldUserProjects.IsNotEmpty())
                   {
                       foreach (var prj in oldUserProjects)
                       {
                           if (model.ProjectIds.IsNotEmpty())
                           {
                               if (model.ProjectIds.Contains(prj.YunProjectGuid))
                               {
                                   model.ProjectIds.Remove(prj.YunProjectGuid);
                               }
                               else
                               {
                                   MsUserToProjectRepository.Remove(prj, true);
                               }
                           }
                           else
                           {
                               MsUserToProjectRepository.Remove(prj, true);
                           }
                       }
                   }

                   if (model.ProjectIds.IsNotEmpty())
                   {
                       model.ProjectIds.ForEach(projectId =>
                       {
                           //添加新的项目关系
                           MsUserToProjectRepository.Add(new Core.Model.Ms.MsUserToProject
                           {
                               YunUserGuid = model.UserId,
                               YunProjectGuid = projectId,
                               MsUserToProjectId = Guid.NewGuid(),
                               IsSendMessage = false
                           });
                       });
                   }
               }

               #endregion 用户项目

               #region 禁用清空用户设备

               if (model.Status == EnumUserStatus.禁用)
               {
                   var userDevices = await SysDeviceRepository.GetDevicesByUserId(new SysDeviceDto() { DeviceUserId = model.UserId });
                   foreach (var device in userDevices)
                   {
                       device.DeviceUserId = null;                                     // 清空用户Id
                       device.DeviceUserName = string.Empty;                           // 清空用户名称
                       device.SetOperatorInfoWhenUpdate();
                       //SysDeviceRepository.Update(device);    // 清空用户设备
                       SysDeviceRepository.Update(device, x => new { x.DeviceUserId, x.DeviceUserName, x.LastUpdatedBy, x.LastUpdatedDate });    // 清空用户设备
                   }
               }

               #endregion 禁用清空用户设备

               isCanSend = true;
               List<Guid> allIDS = new List<Guid>();
               allIDS.AddRange(newProjectIDs);
               allIDS.AddRange(oldUserProjects.Select(i => i.YunProjectGuid));
               allIDS = allIDS.Distinct().ToList();
               allProject = await IMsProjectRepository.WhereAsync(i => allIDS.Contains(i.ProjectId)).ConfigureAwait(false);
           });
            if (isCanSend)
            {
                await UserToProjectMessageService.SaveUserSendMessage(oldUserProjects, model, newProjectIDs, allProject);
                await RedisHelper.Instance.StringDeleteAsync(RedisKeyConstant.ProjectVersionKey(model.YunUserGuid));
            }

            cached.RemoveByRegex(_cacheKeyPre);
        }

        /// <summary>
        /// 获取APP的角色
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<List<SysRoleDto>> GetAppRole(SysUserDto model)
        {
            ApiPageResult apiPageResult = null;
            apiPageResult = await SysRoleRepository.GetPage(new SysRoleCondition() { PageSize = -1 });

            var tempList = apiPageResult.PageData as List<SysRoleDto>;
            return tempList;
        }

        public async Task<SysUserDto> GetUserChangeInfo(UserChangeDto userChangeDto)
        {
            var userInfo = await SysUserRepository.FirstOrDefaultAsync(i => i.YunUserGuid == userChangeDto.YunUserGuid
                        && i.LastUpdatedDate > userChangeDto.SurfaceUserUpdateTime).ConfigureAwait(false);

            return userInfo?.CopyTo<SysUserDto>();
        }

        private async Task<List<SysUserRole>> GetUserNewRoleAsync(SysUserDto model, Guid opeId)
        {
            var allAppRoleList = await GetAppRole(model);//当前应用的所有角色
            var list = new List<SysUserRole>();
            IList<Guid> appUserRoleList = new List<Guid>();

            appUserRoleList = model.RoleList;

            foreach (var roleId in appUserRoleList)
            {
                var newUserDefaultRole = new SysUserRole()
                {
                    UserRoleId = Guid.NewGuid(),
                    UserId = model.YunUserGuid,
                    RoleId = roleId,
                    CreatedBy = opeId,
                    CreatedDate = DateTime.Now,
                    LastUpdatedBy = opeId,
                    LastUpdatedDate = DateTime.Now
                };
                list.Add(newUserDefaultRole);
            }
            return list;
        }

        /// <summary>
        /// 获取用户的角色
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<List<SysUserRoleDto>> GetUserRole(SysUserDto model)
        {
            if (model == null)
                return null;
            ApiPageResult apiPageResult = null;
            apiPageResult = await SysUserRoleRepository.GetPage(new SysUserRoleCondition() { UserId = model.YunUserGuid, PageSize = -1 });
            if (apiPageResult != null)
            {
                var tempList = apiPageResult.PageData as List<SysUserRoleDto>;
                return tempList;
            }
            return null;
        }

        #endregion 缓存配置

        #region 用户

        public async Task<ApiPageResult> GetUserPage(SysUserCondition conditon)
        {
            conditon.CompanyGuid = _tokenModel.CompanyGuid;
            return await SysUserRepository.GetPage2(conditon);
        }

        public async Task<List<SysUserListDto>> GetCompanyUserPage(SysUserCondition conditon)
        {
            conditon.CompanyGuid = _tokenModel.CompanyGuid;
            conditon.Status = SysUser.EnumUserStatus.正常;
            var list = await SysUserRepository.GetCompanyUseListAsync(conditon);
            list = list.Where(i => i.RoleNameList.Contains("测量管理员") || i.RoleNameList.Contains("测量员") || i.RoleNameList.Contains("项目管理员")).ToList();
            return list;
        }

        public async Task<ApiResult> ExistedUser(SysUserDto sysUserDto)
        {
            string userCode = string.Empty;

            if (!string.IsNullOrEmpty(sysUserDto.Email))
            {
                userCode = sysUserDto.Email;
            }
            else if (!string.IsNullOrEmpty(sysUserDto.Code))
            {
                userCode = sysUserDto.Code;
            }
            else if (!string.IsNullOrEmpty(sysUserDto.PhoneNumber))
            {
                userCode = sysUserDto.PhoneNumber;
            }

            var result = new ApiResult();

            if (string.IsNullOrEmpty(sysUserDto.Email))
            {
                return ApiResult.Error(ServiceLocalizer["YB0340"].Value);
            }

            if (!string.IsNullOrEmpty(userCode))
            {
                var res = await SysUserRepository.AnyAsync(p => p.AccountNumber.ToLower() == userCode);
                if (res)
                {
                    return ApiResult.Error(string.Format(ServiceLocalizer["YB0341"].Value, userCode));
                }
            }

            if (!string.IsNullOrEmpty(sysUserDto.Email))
            {
                var res = await SysUserRepository.AnyAsync(p => p.Email.ToLower() == sysUserDto.Email.NullToString().ToLower());
                if (res)
                {
                    return ApiResult.Error(string.Format(ServiceLocalizer["YB0342"].Value, userCode));
                }
            }

            if (!string.IsNullOrEmpty(sysUserDto.PhoneNumber))
            {
                var res = await SysUserRepository.AnyAsync(p => p.PhoneNumber.ToLower() == sysUserDto.PhoneNumber.NullToString().ToLower());
                if (res)
                {
                    return ApiResult.Error(string.Format(ServiceLocalizer["YB0343"].Value, userCode));
                }
            }

            return ApiResult.Success();
        }

        /// <summary>
        /// 修改用户密码
        /// </summary>
        /// <param name="userCode">要修改的用户</param>
        /// <param name="newPassword">新密码</param>
        /// <param name="opeId">操作人</param>
        /// <returns></returns>
        public async Task AdminEditPassword(string userCode, string newPassword, Guid opeId)
        {
            var user = await SysUserRepository.GetUser(new SysUserDto() { UserId = opeId });
            if (user == null)
            {
                throw new OperationException(ServiceLocalizer["YB0345"].Value);
            }

            CheckPassword(newPassword);

            SysUserRepository.Update(t => t.AccountNumber == userCode,
            (Action<SysUser>)(d =>
            {
                d.Password = newPassword.GetMD5();
                d.LastUpdatedBy = opeId;
                d.LastUpdatedDate = DateTime.Now;
            }));
            await UnitOfWork.SaveChangesAsync();

            logger.LogInformation($"【{OperatorProvider.Get().Name}】{ServiceLocalizer["YB0346"].Value}");
        }

        private void CheckPassword(string newPassword)
        {
            if (string.IsNullOrEmpty(newPassword))
            {
                throw new OperationException(ServiceLocalizer["YB0347"].Value);
            }
            if (!string.IsNullOrEmpty(newPassword))
            {
                if (newPassword.Length < 8)
                {
                    throw new OperationException(ServiceLocalizer["YB0348"].Value);
                }

                if (newPassword.Length > 32)
                {
                    throw new OperationException(ServiceLocalizer["YB0349"].Value);
                }
            }

            if (!RegChecker.IsStrongPwd(newPassword))
            {
                throw new OperationException(ServiceLocalizer["YB0350"].Value);
            }
        }

        public string MakePassword(string pwdchars, int pwdlen)
        {
            //判斷隨機密碼的長度
            string tmpstr = "";
            int iRandNum;
            if (pwdlen > pwdchars.Length)
            {
                return ServiceLocalizer["YB0351"].Value + pwdchars.Length;
            }
            Random rnd = new Random();
            for (int i = 0; i < pwdlen; i++)
            {
                iRandNum = rnd.Next(pwdchars.Length);
                tmpstr += pwdchars[iRandNum];
            }
            return tmpstr;
        }

        private string GetRandomPwd()
        {
            string randomchars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
            string char1 = MakePassword(randomchars, 2);
            randomchars = "0123456789";
            string char2 = MakePassword(randomchars, 8);
            return char1 + "@" + char2;
        }

        public async Task<ApiResult> CreateUser(SysUserDto model, Guid opeId)
        {
            model.Code = model.Code.Trim();
            model.Name = model.Name.Trim();
            model.Department = model.Department?.Trim();
            model.Position = model.Position?.Trim();
            Guid newUserId = Guid.NewGuid();
            var result = await ExistedUser(model);

            if (!result.IsSuccess())
            {
                throw new OperationException(result.Message);
            }

            CheckData(model);
            CheckRight(model);
            var entity = model.CopyTo<SysUser>();
            entity.YunUserGuid = newUserId;
            string pwd = GetRandomPwd();
            entity.Password = (pwd).GetMD5();
            entity.Status = SysUser.EnumUserStatus.正常;
            entity.CreatedBy = opeId;
            entity.CreatedDate = DateTime.Now;
            entity.LastUpdatedBy = opeId;
            entity.LastUpdatedDate = DateTime.Now;
            entity.UserType = SysUser.EnumUserType.主账号;
            entity.AccountNumber = model.Email.ToLower();
            entity.RoleNameList = model.RoleNameList.ToJsonStr();
            entity.SysOrgId = _tokenModel.OrgId;
            entity.CompanyNo = _tokenModel.OrgCode;
            entity.Company = model.Department?.Trim();
            entity.IsPasswordNeedToChange = true;
            SysUserRepository.Add(entity);

            if (model.RoleList.Count > 0)
            {
                foreach (var roleId in model.RoleList)
                {
                    await AddUserRole(opeId, newUserId, roleId);
                }
            }

            if (model.SysOrgIds.IsNotEmpty())
            {
                model.SysOrgIds.ForEach(t =>
                {
                    entity.SysOrgUsers.Add(new SysOrgUser { SysOrgId = t.ToGuid(), SysUserId = newUserId });
                });
            }

            if (model.ProjectIds.IsNotEmpty())
            {
                model.ProjectIds.ForEach(projectId =>
                {
                    MsUserToProjectRepository.Add(new Core.Model.Ms.MsUserToProject { YunUserGuid = newUserId, YunProjectGuid = projectId, MsUserToProjectId = Guid.NewGuid() });
                });
            }

            if (model.DeviceIds.IsNotEmpty())
            {
                foreach (var deviceId in model.DeviceIds)
                {
                    var item = await SysDeviceRepository.GetByIdAsync(deviceId);
                    if (item != null)
                    {
                        item.DeviceUserId = newUserId;
                        item.DeviceUserName = model.Name;
                    }
                }
            }

            await UnitOfWork.SaveChangesAsync();

            logger.LogInformation($"【{OperatorProvider.Get().Name}】{ServiceLocalizer["YB0352"].Value + entity.AccountNumber.SetSensitive(2, entity.AccountNumber.IndexOf('@'))}");

            cached.RemoveByRegex(_cacheKeyPre);

            ApiResult apiResult = new ApiResult();
            apiResult.Code = AjaxCode.Success;
            apiResult.Result = newUserId;

            SendMessageToUser(entity, pwd, model.IP);
            await UserToProjectMessageService.AddUserSendMessage(model.IP, model.ProjectIds, model.Name, model.PhoneNumber, model.YunUserGuid);

            return apiResult;
        }

        public void SendMessageToUser(SysUser entity, string pwd, string IP)
        {
            Regex regEmail = new Regex("^\\s*([A-Za-z0-9_-]+(\\.\\w+)*@(\\w+\\.)+\\w{2,5})\\s*$");

            // 并行执行短信和邮件发送
            Parallel.Invoke(async () =>
            {
                if (RegChecker.IsMobilePhone(entity.PhoneNumber))
                {
                    var emailContent = string.Format(ServiceLocalizer["YB0354"].Value, entity.Name, entity.PhoneNumber, entity.Email, pwd, entity.RoleNameList, WebUrl);
                    await smsService.SendSms(IP, entity.PhoneNumber, emailContent);
                }
            }, async () =>
            {
                if (regEmail.Match(entity.Email).Success)
                {
                    int times = 0;
                    bool isSussess = false;
                    string msg = string.Empty;

                    // 失败重试3次
                    while (!isSussess && times < 3)
                    {
                        times = times + 1;
                        try
                        {
                            var emailContent = string.Format(ServiceLocalizer["YB0354"].Value, entity.Name, entity.PhoneNumber, entity.Email, pwd, entity.RoleNameList, WebUrl);
                            await crossEmailService.SendEmail(ServiceLocalizer["YB0353"].Value, entity.Email, emailContent);
                            isSussess = true;
                        }
                        catch (Exception ex)
                        {
                            isSussess = false;
                            msg = ex.Message;
                        }
                    }
                    if (!isSussess)
                    {
                        logger.LogInformation($"邮件发送失败，邮件地址【{entity.Email}】{msg}");
                    }
                }
            });
        }

        /// <summary>
        /// 检查数据有效性
        /// </summary>
        /// <param name="model"></param>
        private void CheckData(SysUserDto model)
        {
            if (string.IsNullOrEmpty(model.Name))
            {
                throw new OperationException(ServiceLocalizer["YB0355"].Value);
            }

            if (!RegChecker.IsName(model.Name))
            {
                throw new OperationException(ServiceLocalizer["YB0356"].Value);
            }

            if (!string.IsNullOrEmpty(model.Name) && model.Name.Length > 50)
            {
                throw new OperationException(string.Format(ServiceLocalizer["YB0357"].Value, model.Name.Length));
            }

            if (string.IsNullOrEmpty(model.PhoneNumber))
            {
                throw new OperationException(ServiceLocalizer["YB0360"].Value);
            }

            if (!RegChecker.IsMobilePhone(model.PhoneNumber))
            {
                throw new OperationException(ServiceLocalizer["YB0358"].Value);
            }

            //其他用户使用了该手机号
            bool otherPhoneUsed = SysUserRepository.Any(p => p.PhoneNumber.ToLower() == model.PhoneNumber && p.YunUserGuid != model.UserId);
            if (otherPhoneUsed == true)
            {
                throw new OperationException(ServiceLocalizer["YB0359"].Value);
            }

            //用户使用了手机号 并且 usercode是手机号，则更新userocde
            if (RegChecker.IsMobilePhone((model.Code)))
            {
                try
                {
                    bool codeIsPhone = RegChecker.IsMobilePhone(SysUserRepository.GetById(model.UserId).AccountNumber);
                    if (codeIsPhone == true)
                    {
                        model.Code = model.PhoneNumber;
                    }
                }
                catch
                {
                    //
                }
            }

            if (string.IsNullOrEmpty(model.Email))
            {
                throw new OperationException(ServiceLocalizer["YB0364"].Value);
            }

            if (!RegChecker.IsEmail(model.Email))
            {
                throw new OperationException(ServiceLocalizer["YB0361"].Value);
            }
            if (model.Email.Length > 50)
            {
                throw new OperationException(string.Format(ServiceLocalizer["YB0362"].Value, model.Email.Length));
            }
            //其他用户使用了该邮箱
            bool otherEmailUsed = SysUserRepository.Any(p => p.Email.ToLower() == model.Email && p.YunUserGuid != model.UserId);
            if (otherEmailUsed == true)
            {
                throw new OperationException(ServiceLocalizer["YB0363"].Value);
            }

            if (string.IsNullOrEmpty(model.Position))
            {
                throw new OperationException(ServiceLocalizer["YB0366"].Value);
            }

            if (model.Position.Length > 50)
            {
                throw new OperationException(string.Format(ServiceLocalizer["YB0365"].Value, model.Position.Length));
            }

            if (model.RoleNameList == null || model.RoleNameList.Count == 0)
            {
                throw new OperationException(ServiceLocalizer["YB0367"].Value);
            }

            foreach (var roleName in model.RoleNameList)
            {
                if (!RoleNameList.Contains(roleName))
                {
                    throw new OperationException(string.Format(ServiceLocalizer["YB0368"].Value, roleName));
                }
            }
        }

        private static List<string> RoleNameList = new List<string>() { "公司管理员", "测量管理员", "项目管理员", "测量员" };

        /// <summary>
        /// 检查权限
        /// </summary>
        /// <param name="model"></param>
        public void CheckRight(SysUserDto model)
        {
            string roleName = _tokenModel.RoleNameList;

            if (model.UserId != Guid.Empty && model.YunUserGuid == Guid.Empty)
            {
                model.YunUserGuid = model.UserId;
            }

            if (_tokenModel.RoleNameList.Contains("公司管理员") && model.RoleNameList.Contains("公司管理员"))
            {
                throw new OperationException(ServiceLocalizer["YB0369"].Value);
            }

            if (_tokenModel.RoleNameList.Contains("测量管理员") && model.RoleNameList.Contains("公司管理员"))
            {
                throw new OperationException(ServiceLocalizer["YB0369"].Value);
            }
            if (_tokenModel.RoleNameList.Contains("测量管理员") && model.RoleNameList.Contains("测量管理员") && model.YunUserGuid != _tokenModel.YunUserGuid)
            {
                throw new OperationException(string.Format(ServiceLocalizer["YB0372"].Value, roleName));
            }

            if (_tokenModel.RoleNameList.Contains("项目管理员"))
            {
                if (model.RoleNameList.Contains("公司管理员"))
                {
                    throw new OperationException(ServiceLocalizer["YB0369"].Value);
                }
                else if (model.RoleNameList.Contains("测量管理员"))
                {
                    throw new OperationException(string.Format(ServiceLocalizer["YB0372"].Value, roleName));
                }
                else if (model.RoleNameList.Contains("项目管理员"))
                {
                    if (model.YunUserGuid != _tokenModel.YunUserGuid)
                    {
                        throw new OperationException(string.Format(ServiceLocalizer["YB0433"].Value, roleName));
                    }
                }
                else if (model.RoleNameList.Contains("测量员"))
                {
                    throw new OperationException(string.Format(ServiceLocalizer["YB0434"].Value, roleName));
                }
            }

            if (_tokenModel.RoleNameList.Contains("测量员"))
            {
                if (model.RoleNameList.Contains("公司管理员"))
                {
                    throw new OperationException(ServiceLocalizer["YB0369"].Value);
                }
                else if (model.RoleNameList.Contains("测量管理员"))
                {
                    throw new OperationException(string.Format(ServiceLocalizer["YB0372"].Value, roleName));
                }
                else if (model.RoleNameList.Contains("项目管理员"))
                {
                    throw new OperationException(string.Format(ServiceLocalizer["YB0433"].Value, roleName));
                }
                else if (model.RoleNameList.Contains("测量员"))
                {
                    if (model.YunUserGuid != _tokenModel.YunUserGuid)
                    {
                        throw new OperationException(string.Format(ServiceLocalizer["YB0434"].Value, roleName));
                    }
                }
            }
        }

        private async Task AddUserRole(Guid opeId, Guid newUserId, Guid roleId)
        {
            var newUserDefaultRole = new SysUserRole()
            {
                UserRoleId = Guid.NewGuid(),
                UserId = newUserId,
                RoleId = roleId,
                CreatedBy = opeId,
                CreatedDate = DateTime.Now,
                LastUpdatedBy = opeId,
                LastUpdatedDate = DateTime.Now
            };
            SysUserRoleRepository.Add(newUserDefaultRole);
        }

        #region 删除用户

        public async Task DeleteUsers(List<SysUserDto> list, Guid opeId)
        {
            foreach (var user in list)
            {
                var el = SysUserRepository.GetById(user.UserId);
                if (el != null)
                {
                    if (el.AccountNumber.ToLower() == ForbidUserCode || el.UserType == SysUser.EnumUserType.管理员)
                    {
                        throw new OperationException(string.Format(ServiceLocalizer["YB0376"].Value, ForbidUserCode));
                    }

                    el.Email = $"{el.Email}-{el.YunUserGuid.ToString()}";
                    el.AccountNumber = $"{el.AccountNumber}-{el.YunUserGuid.ToString()}";
                    el.PhoneNumber = $"{el.PhoneNumber}-{el.YunUserGuid.ToString()}";
                    el.Name = $"{el.Name}-{el.YunUserGuid.ToString()}";
                    SysUserRepository.Remove(el);
                }

                #region 清空用户设备

                var userDevices = await SysDeviceRepository.GetDevicesByUserId(new SysDeviceDto() { DeviceUserId = user.UserId });
                foreach (var device in userDevices)
                {
                    // 清空用户Id
                    device.DeviceUserId = null;
                    // 清空用户名称
                    device.DeviceUserName = null;
                    device.SetOperatorInfoWhenUpdate();
                    SysDeviceRepository.Update(device, x => new { x.DeviceUserId, x.DeviceUserName, x.LastUpdatedBy, x.LastUpdatedDate });    // 清空用户设备
                }

                #endregion 清空用户设备
            }
            await UnitOfWork.SaveChangesAsync();

            logger.LogInformation($"【{OperatorProvider.Get().Name}】{ServiceLocalizer["YB0377"].Value}");

            cached.RemoveByRegex(_cacheKeyPre);
        }

        public async Task DeleteUser(Guid userId, Guid opeId)
        {
            var el = SysUserRepository.GetById(userId);
            if (el != null)
            {
                if (el.AccountNumber.ToLower() == ForbidUserCode || el.UserType == SysUser.EnumUserType.管理员)
                {
                    throw new OperationException(string.Format(ServiceLocalizer["YB0376"].Value, ForbidUserCode));
                }

                SysUserRepository.Remove(el, realDelete: true);
                await UnitOfWork.SaveChangesAsync();
                logger.LogInformation($"【{OperatorProvider.Get().Name}】{ServiceLocalizer["YB0377"].Value}");
                cached.RemoveByRegex(_cacheKeyPre);
            }
        }

        #endregion 删除用户

        #region 用户登录锁定检查

        /// <summary>
        /// 用户登录锁
        /// </summary>
        private static readonly object UserLoginLocker = new object();

        /// <summary>
        /// 允许的连续的最大错误登录次数，后锁定20分钟
        /// </summary>
        private static int MaxErrorTime = 6;

        /// <summary>
        /// 锁定时间,单位分钟
        /// </summary>
        private static int LockMinutes = 5;

        private static Dictionary<string, LockerInfo> lockerUser = new Dictionary<string, LockerInfo>();

        private static void SetLockerUser(string key, LockerInfo lockerInfo)
        {
            if (lockerUser != null)
            {
                if (!lockerUser.ContainsKey(key))
                {
                    lockerUser.Add(key, lockerInfo);
                }
                else
                {
                    lockerUser[key] = lockerInfo;
                }
            }
        }

        /// <summary>
        /// 检查锁定用户
        /// </summary>
        /// <param name="userDto"></param>
        /// <param name="loginSucced"></param>
        /// <param name="onlyCheckStatus"></param>
        public void CheckLockUser(SysUserDto userDto, bool loginSucced, bool onlyCheckStatus = false)
        {
            lock (UserLoginLocker)
            {
                string key = "UserService-CheckLockUser-" + userDto.Code;
                LockerInfo lockerInfo = lockerUser.GetValueOrDefault(key);
                if (onlyCheckStatus == true)
                {
                    if (lockerInfo != null)
                    {
                        if (lockerInfo.Status == LockStatus.Locked && lockerInfo.LockToDateTime >= DateTime.Now)
                        {
                            throw new OperationException(string.Format(StartupServer.ServiceLocalizer["YB0378"].Value, lockerInfo.LockToDateTime.AddMinutes(-DateTime.Now.Minute).Minute));
                        }
                        else if (lockerInfo.Status == LockStatus.Locked && lockerInfo.LockToDateTime < DateTime.Now)
                        {
                            lockerUser.Remove(key);//移出锁定
                        }
                    }
                    return;
                }

                if (loginSucced == false)//登录失败
                {
                    if (lockerInfo == null)//第一次错误
                    {
                        lockerInfo = new LockerInfo()
                        {
                            ErrorTime = 1,
                            LockToDateTime = DateTime.Now.AddMinutes(LockMinutes),
                            LockUserCode = userDto.Code
                        };
                        SetLockerUser(key, lockerInfo);
                        throw new OperationException(string.Format(StartupServer.ServiceLocalizer["YB0379"].Value, MaxErrorTime - 1));
                    }
                    else//多次错误
                    {
                        var newLockerInfo = new LockerInfo()
                        {
                            ErrorTime = lockerInfo.ErrorTime + 1,
                            LockToDateTime = DateTime.Now.AddMinutes(LockMinutes),
                            LockUserCode = userDto.Code
                        };

                        if (lockerInfo.ErrorTime + 1 >= MaxErrorTime)
                        {
                            newLockerInfo.Status = LockStatus.Locked;
                            SetLockerUser(key, newLockerInfo);
                            throw new OperationException(string.Format(StartupServer.ServiceLocalizer["YB0380"].Value, MaxErrorTime, LockMinutes));
                        }
                        else
                        {
                            SetLockerUser(key, newLockerInfo);
                        }

                        throw new OperationException(string.Format(StartupServer.ServiceLocalizer["YB0379"].Value, MaxErrorTime - newLockerInfo.ErrorTime));
                    }
                }
                else//登录成功
                {
                    lockerUser.Remove(key);
                }
            }
        }

        /// <summary>
        /// 获取用户
        /// </summary>
        /// <param name="account">账号</param>
        /// <param name="password">密码</param>
        /// <returns></returns>
        internal async Task<SysUserDto> FindUser(string account, string password)
        {
            return await FindUser(new SysUserDto() { Code = account, Password = password });
        }

        /// <summary>
        /// 查询用户并激活设备
        /// </summary>
        /// <param name="userID"></param>
        /// <param name="userKeyNo"></param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        public async Task<SysUserDto> FindUserByIDAndSetDeviceAtive(Guid userID, string userKeyNo)
        {
            var user = await SysUserRepository.FirstOrDefaultAsync(i => i.YunUserGuid == userID);
            if (user is null)
                return null;

            var device = await SysDeviceRepository.FirstOrDefaultAsync(i => i.SysOrgId == user.SysOrgId && i.EncryptedDogNumber == userKeyNo && !i.IsDeleted);
            if (device is null)
            {
                logger.LogInformation($"公司Id：{user.SysOrgId}，加密狗编号：{userKeyNo}");
                throw new OperationException(ServiceLocalizer["YB0384"].Value);
            }

            if (device.IsDeleted)
            {
                throw new OperationException(ServiceLocalizer["YB0382"].Value);
            }

            try
            {
                device.IsActive = true;
                device.ActiveDate = DateTime.Now;
                SysDeviceRepository.Update(device);
                var affrows = await UnitOfWork.SaveChangesAsync();
                if (affrows > 0)
                {
                    logger.LogInformation($"激活设备记录，加密狗：{userKeyNo}，设备GUID：{device.DeviceGuid}");
                    await sysDeviceService.PushDeviceQueueMessage(device.DeviceGuid);
                }
            }
            catch (Exception ex)
            {
                logger.LogError(ex.Message, ex);
                throw new OperationException(ServiceLocalizer["YB0383"].Value);
            }
            var dto = user.CopyTo<SysUserDto>();
            dto.Password = "";

            #region 获取角色

            var role = user.RoleNameList;
            var firstIndex = role.IndexOf('\"');
            var lastIndex = role.LastIndexOf('\"');
            var roleName = role.Substring(firstIndex + 1, lastIndex - firstIndex - 1).Split(',').ToList();

            dto.RoleNameList = roleName;

            #endregion 获取角色

            return dto;
        }

        /// <summary>
        /// 认证调用
        /// </summary>
        /// <param name="userDto"></param>
        /// <returns></returns>
        public async Task<SysUserDto> FindUser(SysUserDto userDto)
        {
            SysUser record = SysUserRepository.Where(t => (t.AccountNumber == userDto.Code || t.PhoneNumber == userDto.Code || t.Email == userDto.Code)
                          && t.Password == userDto.Password.GetMD5() && t.IsDeleted == false).FirstOrDefault();

            if (record != null)
            {
                CheckLockUser(userDto, true);
                var dto = record.CopyTo<SysUserDto>();
                dto.RoleNameList = record.RoleNameList.ToObject<List<string>>() ?? new List<string>();
                dto.RoleList = new List<Guid>();
                dto.RoleCodeList = new List<string>();
                dto.SysOrgIds = (new string[] { record.SysOrgId }).ToList();
                dto.SysOrgCodes = (new string[] { record.CompanyNo }).ToList();
                return dto;
            }
            else
            {
                CheckLockUser(userDto, false);
                return null;
            }
        }

        /// <summary>
        /// 密码直接密文匹配
        /// </summary>
        /// <param name="userDto"></param>
        /// <returns></returns>
        public async Task<SysUserDto> FindUser2(SysUserDto userDto)
        {
            Guid yunUserGuid = AesCoreHelper.Decrypt(userDto.RegisterId, AesCoreHelper.Sceret).ToGuid();

            var record = await SysUserRepository.GetAll()
                    .Where(t => t.YunUserGuid == yunUserGuid && t.IsDeleted == false)
                    .FirstOrDefaultAsync().ConfigureAwait(false);
            if (record != null)
            {
                CheckLockUser(userDto, true);
                var dto = record.CopyTo<SysUserDto>();
                return dto;
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// 密码直接密文匹配
        /// </summary>
        /// <param name="userDto"></param>
        /// <param name="dogNum"></param>
        /// <returns></returns>
        public async Task<SysUserDto> FindUser(SysUserDto userDto, string dogNum)
        {
            var record = await SysUserRepository.GetAll()
                    .Where(t => t.YunUserGuid == userDto.YunUserGuid && t.IsDeleted == false)
                    .FirstOrDefaultAsync().ConfigureAwait(false);

            if (record == null) return null;

            var isHave = await SysDeviceRepository.AnyAsync(i => i.SysOrgId == record.SysOrgId && i.EncryptedDogNumber == dogNum);

            if (!isHave)
                throw new OperationException(ServiceLocalizer["YB0385"].Value);

            CheckLockUser(userDto, true);
            var dto = record.CopyTo<SysUserDto>();
            try
            {
                dto.RoleNameList = record.RoleNameList.ToObject<List<string>>();
            }
            catch (Exception ex)
            {
                logger.LogError(ex, $"FindUser: {ex.Message} {record.RoleNameList}");
                return null;
            }
            return dto;
        }

        /// <summary>
        /// 获取单个用户数据
        /// </summary>
        /// <param name="userDto"></param>
        /// <returns></returns>
        public async Task<SysUserListDto> GetUser(SysUserDto userDto)
        {
            var userInfo = await SysUserRepository.GetUser(userDto).ConfigureAwait(false);
            if (userInfo != null)
            {
                var condition = new UserProjectStatisDto();
                condition.YunUserGuid = userDto.UserId;
                var projectInfo = await statisService.GetUserProjectInfo(condition);
                userInfo.Projects = projectInfo;
            }
            return userInfo;
        }

        /// <summary>
        /// 退出登录，删除缓存中的tokenid
        /// </summary>
        /// <param name="tokenModel"></param>
        /// <param name="expiresdate"></param>
        /// <param name="action"></param>
        /// <returns></returns>
        public async Task Logout(OperatorInfo tokenModel, DateTime expiresdate, Action action)
        {
            logger.LogInformation($"【{OperatorProvider.Get().Name}】{ServiceLocalizer["YB0386"].Value}");
            cached.Remove(tokenModel.LogId);
            cached.Set<bool>(tokenModel.YunUserGuid + tokenModel.TokenId, true, new TimeSpan(expiresdate.Ticks - DateTime.Now.Ticks));
            if (action != null)
                action();
        }

        /// <summary>
        /// 退出登录，删除缓存中的tokenid
        /// </summary>
        /// <param name="userCodeList"></param>
        /// <returns></returns>
        public async Task Logout(List<string> userCodeList)
        {
            logger.LogInformation($"【{OperatorProvider.Get().Name}】{ServiceLocalizer["YB0386"].Value}");
            foreach (var userCode in userCodeList)
            {
                cached.Remove(userCode);
            }
        }

        #region 缓存配置

        /// <summary>
        /// 获取页面的用户当前缓存键
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        private string GetUserLogCacheKey(LogQueryView obj)
        {
            return $"GetUserLogCacheKey-{_tokenModel.LogId}-{obj.ToJsonStr().GetMD5()}";
        }

        #endregion 缓存配置

        public async Task<ApiPageResult> GetUserLog(LogQueryView logQueryView)
        {
            string cacheKey = GetUserLogCacheKey(logQueryView);
            var cacheObj = cached.Get<ApiPageResult>(cacheKey);

            if (cacheObj != null)
            {
                return cacheObj;
            }
            else
            {
                if (logQueryView.CreatedDateFrom != null && logQueryView.CreatedDateTo != null)
                {
                    if (logQueryView.CreatedDateFrom > logQueryView.CreatedDateTo)
                    {
                        throw new OperationException(ServiceLocalizer["YB0387"].Value);
                    }
                }
                var result = await LogRepository.GetPage(logQueryView);
                cached.Set(cacheKey, result, TimeSpan.FromMinutes(1), false);
                return result;
            }
        }

        #endregion 用户登录锁定检查

        #region 激活

        /// <summary>
        /// 获取手机验证码
        /// </summary>
        /// <param name="registerDto"></param>
        /// <returns></returns>
        public async Task<ApiResult> VerfifyCode_Get(RegisterDto registerDto)
        {
            if (registerDto.Account.IsNullOrWhiteSpace())
                throw new OperationException(ServiceLocalizer["YB0388"].Value);
            var account = registerDto.Account.ToLower();
            var user = await SysUserRepository.GetAll()
                .FirstOrDefaultAsync(t => !t.IsDeleted && (t.Email == registerDto.Account || t.PhoneNumber == registerDto.Account || t.Name == account));

            Regex regEmail = new Regex("^\\s*([A-Za-z0-9_-]+(\\.\\w+)*@(\\w+\\.)+\\w{2,5})\\s*$");
            var title = string.Empty;
            switch (registerDto.OperationType)
            {
                case 0:
                    {
                        if (user.IsNotNull())
                        {
                            return new ApiResult(AjaxCode.Exsit, ServiceLocalizer["YB0389"].Value);
                        }
                        else
                        {
                            title = "Please verify your device";
                        }
                        break;
                    }
                case 1:
                    {
                        if (user.IsNotNull())
                        {
                            return new ApiResult(AjaxCode.Exsit, ServiceLocalizer["YB0389"].Value);
                        }
                        else
                        {
                            title = "Please confirm to modify your account";
                        }
                        break;
                    }
                case 2:
                    {
                        if (user.IsNotNull())
                        {
                            return new ApiResult(AjaxCode.Exsit, ServiceLocalizer["YB0389"].Value);
                        }
                        else
                        {
                            title = "Please confirm to modify your account";
                        }
                        break;
                    }
                case 3:
                    {
                        if (user.IsNull())
                        {
                            return new ApiResult(AjaxCode.Error, ServiceLocalizer["YB0390"].Value);
                        }
                        else
                        {
                            title = "Please confirm to modify your account";
                        }
                        break;
                    }
                default:
                    {
                        if (user.IsNull())
                        {
                            return new ApiResult(AjaxCode.Error, ServiceLocalizer["YB0390"].Value);
                        }
                        else
                        {
                            title = "Please confirm to modify your account";
                        }
                        break;
                    }
            }

            string code = string.Empty;
            try
            {
                code = verifyCode.GetCode(registerDto.Account, verifyCodeMinute, maxNumPerAccount);
            }
            catch (Exception ex)
            {
                throw new OperationException(ServiceLocalizer["YB060201"].Value, ex);
            }
            if (code == "busy")
                return new ApiResult(AjaxCode.Unauthorized, ServiceLocalizer["YB0391"].Value);

            if (regEmail.Match(registerDto.Account).Success)
            {
                if (registerDto.OperationType == 3)
                {
                    if (user.Email.NullToString().ToLower().Trim() != registerDto.Account.NullToString().ToLower().Trim())
                    {
                        return ApiResult.Error(ServiceLocalizer["YB22060601"].Value);
                    }
                }

                await crossEmailService.SendEmail(title, registerDto.Email.NullToString().Trim(), string.Format(ServiceLocalizer["YB0392"].Value, code, verifyCodeMinute));
                return ApiResult.Success();
            }
            else if (RegChecker.IsMobilePhone(registerDto.Account))//如果是手机号
            {
                if (registerDto.OperationType == 3)
                {
                    if (user.PhoneNumber.NullToString().ToLower().Trim() != registerDto.Account.NullToString().ToLower().Trim())
                    {
                        return ApiResult.Error(ServiceLocalizer["YB22060601"].Value);
                    }
                }

                await smsService.SendSms(registerDto.IP, registerDto.Account, string.Format(ServiceLocalizer["YB0392"].Value, code, verifyCodeMinute));
                return ApiResult.Success();
            }
            else
            {
                return ApiResult.Error(ServiceLocalizer["YB0393"].Value);
            }
        }

        public async Task<ApiResult> VerifyCode_Check(RegisterDto registerDto)
        {
            var resp = verifyCode.CheckCode(registerDto.Account, registerDto.VerifyCode);
            if (resp == 0)
            {
                return new ApiResult(AjaxCode.Fail, ServiceLocalizer["YB0210"].Value);
            }
            if (resp == -1)
            {
                return new ApiResult(AjaxCode.Fail, ServiceLocalizer["YB0211"].Value);
            }
            if (registerDto.OperationType == 0)
            {
                var device = await SysDeviceRepository.FirstOrDefaultAsync(t => t.EncryptedDogNumber == registerDto.EncryptedDogNumber && t.EncryptedDogType == registerDto.EncryptedDogType);
                if (device.IsNull())
                {
                    return new ApiResult(AjaxCode.Unauthorized, ServiceLocalizer["YB0394"].Value);
                }

                if (device.IsActive)
                {
                    return new ApiResult(AjaxCode.Exsit, ServiceLocalizer["YB0395"].Value);
                }

                if (device.IsDeleted)
                {
                    return new ApiResult(AjaxCode.Unauthorized, ServiceLocalizer["YB0396"].Value);
                }

                var binding = await SysDeviceUserRepository.FirstOrDefaultAsync(t => t.DeviceGuid == device.DeviceGuid);
                if (binding.IsNotNull())
                {
                    return new ApiResult(AjaxCode.Exsit, ServiceLocalizer["YB0397"].Value);
                }

                var userId = Guid.NewGuid();
                bool existed = false;
                if (!string.IsNullOrEmpty(registerDto.Email))
                {
                    existed = await SysUserRepository.AnyAsync(p => p.AccountNumber == registerDto.Email && p.IsDeleted == false);
                    if (existed)
                    {
                        return new ApiResult(AjaxCode.Exsit, ServiceLocalizer["YB0342"].Value);
                    }
                }

                if (!string.IsNullOrEmpty(registerDto.PhoneNumber))
                {
                    existed = await SysUserRepository.AnyAsync(p => p.AccountNumber == registerDto.PhoneNumber && p.IsDeleted == false);
                    if (existed)
                    {
                        return new ApiResult(AjaxCode.Exsit, ServiceLocalizer["YB0343"].Value);
                    }
                }

                CheckPassword(registerDto.Password);

                List<string> roles = new List<string>();
                roles.Add("人工测量员");
                var user = new SysUser
                {
                    YunUserGuid = userId,
                    Password = registerDto.Password.GetMD5(),
                    Status = SysUser.EnumUserStatus.正常,
                    UserType = SysUser.EnumUserType.主账号,
                    PhoneNumber = registerDto.PhoneNumber,
                    Email = registerDto.Email,
                    Name = registerDto.Account,
                    IsLocked = SysUser.EnumIsLocked.正常,
                    AccountNumber = registerDto.Account,
                    RoleNameList = roles.ToJsonStr(),
                };
                device.ActiveUserGuid = userId;
                device.IsActive = true;
                device.ActiveDate = DateTime.Now;

                SysDeviceUserRepository.Add(new SysDeviceUser { UserGuid = userId, DeviceGuid = device.DeviceGuid });

                SysUserRepository.Add(user);

                SysDeviceRepository.Update(device);

                await UnitOfWork.SaveChangesAsync();
                SysDeviceUserDto sysDeviceUserDto = new SysDeviceUserDto();
                sysDeviceUserDto.DeviceGuid = device.DeviceGuid;
                sysDeviceUserDto.YunUserGuid = userId;
                return ApiResult.Success().SetData(sysDeviceUserDto);
            }
            else
            {
                return ApiResult.Success("OK");
            }
        }

        public async Task<ApiResult> Activate(RegisterDto registerDto)
        {
            var user = await SysUserRepository
               .FirstOrDefaultAsync(t => (t.Email == registerDto.Email || t.PhoneNumber == registerDto.PhoneNumber) && t.Password == registerDto.Password.GetMD5());

            if (user.IsNull())
                return new ApiResult(AjaxCode.Fail, ServiceLocalizer["YB0398"].Value);

            var device = await SysDeviceRepository.FirstOrDefaultAsync(t => t.EncryptedDogNumber == registerDto.EncryptedDogNumber && t.EncryptedDogType == registerDto.EncryptedDogType);
            if (device.IsNull())
            {
                return new ApiResult(AjaxCode.Unauthorized, ServiceLocalizer["YB0394"].Value);
            }
            if (device.IsActive)
            {
                return new ApiResult(AjaxCode.Exsit, ServiceLocalizer["YB0395"].Value);
            }

            device.ActiveUserGuid = user.YunUserGuid;
            device.IsActive = true;
            device.ActiveDate = DateTime.Now;
            SysDeviceRepository.Update(device);

            SysDeviceUserRepository.Add(new SysDeviceUser { UserGuid = user.YunUserGuid, DeviceGuid = device.DeviceGuid });
            await UnitOfWork.SaveChangesAsync();

            await sysDeviceService.PushDeviceQueueMessage(device.DeviceGuid);

            return ApiResult.Success(ServiceLocalizer["YB0399"].Value).SetData(device.DeviceGuid);
        }

        public async Task<ApiResult> GetDeviceGuid(VerifyDeviceDto verifyDeviceDto)
        {
            var device = await SysDeviceRepository.FirstOrDefaultAsync(t => t.EncryptedDogNumber == verifyDeviceDto.EncryptedDogNumber && t.EncryptedDogType == verifyDeviceDto.EncryptedDogType);
            if (device.IsNull())
            {
                return new ApiResult(AjaxCode.Unauthorized, ServiceLocalizer["YB0394"].Value);
            }
            else
            {
                return ApiResult.Success("OK").SetData(device.DeviceGuid);
            }
        }

        public async Task<ApiResult> ReActivate(VerifyDeviceDto verifyDeviceDto)
        {
            var user = await SysUserRepository
               .FirstOrDefaultAsync(t => t.AccountNumber == verifyDeviceDto.Account);

            var device = await SysDeviceRepository.FirstOrDefaultAsync(t => t.EncryptedDogNumber == verifyDeviceDto.EncryptedDogNumber && t.EncryptedDogType == verifyDeviceDto.EncryptedDogType);
            if (device.IsNull())
            {
                return new ApiResult(AjaxCode.Unauthorized, ServiceLocalizer["YB0394"].Value);
            }

            var binding = await SysDeviceUserRepository.FirstOrDefaultAsync(t => t.DeviceGuid == device.DeviceGuid);

            if (user.IsNull())
            {
                if (binding.IsNotNull())
                {
                    return new ApiResult(AjaxCode.Exsit, ServiceLocalizer["YB0400"].Value);
                }
                var userId = Guid.NewGuid();
                var code = verifyDeviceDto.Account.ToLower();//verifyDeviceDto.Account.Split('@')[0];
                var newuser = new SysUser
                {
                    YunUserGuid = userId,
                    Password = verifyDeviceDto.Password,
                    Status = SysUser.EnumUserStatus.正常,
                    UserType = SysUser.EnumUserType.主账号,
                    PhoneNumber = verifyDeviceDto.Account,
                    Email = verifyDeviceDto.Account,
                    Name = verifyDeviceDto.Account,
                    IsLocked = SysUser.EnumIsLocked.正常,
                    AccountNumber = code,
                    CreatedBy = userId,
                    LastUpdatedBy = userId,
                };
                device.ActiveUserGuid = userId;
                SysDeviceUserRepository.Add(new SysDeviceUser { UserGuid = userId, DeviceGuid = device.DeviceGuid });
                SysUserRepository.Add(newuser);
            }
            else
            {
                if (user.Password != verifyDeviceDto.Password)
                {
                    return new ApiResult(AjaxCode.Error, ServiceLocalizer["YB0401"].Value);
                }
                if (binding.IsNull())
                {
                    SysDeviceUserRepository.Add(new SysDeviceUser { UserGuid = user.YunUserGuid, DeviceGuid = device.DeviceGuid });
                }
                else
                {
                    if (binding.UserGuid != user.YunUserGuid)
                    {
                        return new ApiResult(AjaxCode.Exsit, ServiceLocalizer["YB0400"].Value);
                    }
                }
                device.ActiveUserGuid = user.YunUserGuid;
            }

            device.IsActive = true;
            device.ActiveDate = DateTime.Now;
            await UnitOfWork.SaveChangesAsync();

            await sysDeviceService.PushDeviceQueueMessage(device.DeviceGuid);
            return ApiResult.Success(ServiceLocalizer["YB0402"].Value).SetData(device.DeviceGuid);
        }

        public async Task<ApiResult> UnActivate(RegisterDto registerDto)
        {
            try
            {
                var actionId = Guid.NewGuid();
                Logger.Info($"Actionid:{actionId}开始进入UnActivate：信息" + Newtonsoft.Json.JsonConvert.SerializeObject(registerDto));
                var user = await SysUserRepository
                   .FirstOrDefaultAsync(t => t.Email == registerDto.Email && t.Password == registerDto.Password.GetMD5());
                Logger.Info($"Actionid:{actionId}获取用户信息，");
                if (user.IsNull())
                    return new ApiResult(AjaxCode.Fail, ServiceLocalizer["YB0398"].Value);

                var device = await SysDeviceRepository.FirstOrDefaultAsync(t => t.EncryptedDogNumber == registerDto.EncryptedDogNumber && t.EncryptedDogType == registerDto.EncryptedDogType);
                if (device.IsNull())
                {
                    return new ApiResult(AjaxCode.Unauthorized, ServiceLocalizer["YB0394"].Value);
                }
                if (!device.IsActive)
                {
                    return new ApiResult(AjaxCode.Exsit, ServiceLocalizer["YB0403"].Value);
                }
                Logger.Info($"Actionid:{actionId}获取设备信息，");
                var binding = await SysDeviceUserRepository
                    .FirstOrDefaultAsync(t =>
                    t.DeviceGuid == device.DeviceGuid
                    && t.UserGuid == user.YunUserGuid
                    );
                if (binding.IsNotNull())
                {
                    SysDeviceUserRepository.Remove(binding);
                }
                Logger.Info($"Actionid:{actionId}获取关联关系，");
                device.IsActive = false;
                device.ActiveDate = null;
                device.ActiveUserGuid = null;
                device.LastUpdatedDate = DateTime.Now;
                SysDeviceRepository.Update(device);

                SysUserRepository.Remove(user, true);
                Logger.Info($"Actionid:{actionId}更新和移除数据");
                await UnitOfWork.SaveChangesAsync();
                Logger.Info($"Actionid:{actionId}结束，将返回结果");

                await sysDeviceService.PushDeviceQueueMessage(device.DeviceGuid);

                return ApiResult.Success(ServiceLocalizer["YB0404"].Value).SetData(device.DeviceGuid);
            }
            catch (Exception ex)
            {
                Logger.Info($"UnActivate exception:" + Newtonsoft.Json.JsonConvert.SerializeObject(ex));
                return ApiResult.Error().SetData(Guid.NewGuid().ToString());
            }
        }

        public async Task<ApiResult> VerifyDevice(VerifyDeviceDto verifyDeviceDto)
        {
            var device = await SysDeviceRepository.FirstOrDefaultAsync(t => t.EncryptedDogNumber == verifyDeviceDto.EncryptedDogNumber && t.EncryptedDogType == verifyDeviceDto.EncryptedDogType);
            if (device.IsNull())
            {
                return new ApiResult(AjaxCode.Unauthorized, ServiceLocalizer["YB0394"].Value);
            }
            if (device.DeviceGuid != verifyDeviceDto.DeviceGuid)
            {
                return new ApiResult(AjaxCode.Fail, ServiceLocalizer["YB0406"].Value);
            }

            device.IsActive = true;
            device.LastUpdatedDate = DateTime.Now;
            SysDeviceRepository.Update(device);
            await UnitOfWork.SaveChangesAsync();

            await sysDeviceService.PushDeviceQueueMessage(device.DeviceGuid);
            return ApiResult.Success(ServiceLocalizer["YB0407"].Value).SetData(device.DeviceGuid);
        }

        public async Task<ApiResult> GetSelf()
        {
            var userId = OperatorProvider.Get()?.YunUserGuid;

            SysUser sysUser = await SysUserRepository.GetByIdAsync(userId);
            sysUser.Password = "******";
            return ApiResult.Success("OK").SetData(sysUser);
        }

        public async Task<ApiResult> ChangeEmail(RegisterDto registerDto)
        {
            var resp = verifyCode.CheckCode(registerDto.Email, registerDto.VerifyCode);
            if (resp == 0)
            {
                return new ApiResult(AjaxCode.Fail, ServiceLocalizer["YB0210"].Value);
            }
            if (resp == -1)
            {
                return new ApiResult(AjaxCode.Fail, ServiceLocalizer["YB0211"].Value);
            }
            var userId = OperatorProvider.Get()?.YunUserGuid;
            var entity = SysUserRepository.Update(t => t.YunUserGuid == userId, d =>
            {
                d.Email = registerDto.Email.ToLower();
                d.Name = registerDto.Email.ToLower();
                d.AccountNumber = registerDto.Email.ToLower();
            });
            var count = await UnitOfWork.SaveChangesAsync();
            return ApiResult.Success(ServiceLocalizer["YB0212"].Value).SetData(entity);
        }

        /// <summary>
        /// 云端用户修改密码接口
        /// </summary>
        /// <param name="registerDto"></param>
        /// <returns></returns>
        public async Task<ApiResult> ResetCloudUserPassword(RegisterDto registerDto)
        {
            if (registerDto.Email.IsNullOrWhiteSpace())
                return new ApiResult(AjaxCode.Fail, ServiceLocalizer["YB0408"].Value);
            var pwd = registerDto.Password;
            try
            {
                RSACryptoService rsa2 = new RSACryptoService(RSACryptoService.DefaultPrivateKey, RSACryptoService.DefaultPublicKey);
                registerDto.Password = rsa2.Decrypt(registerDto.Password);
            }
            catch
            {
                registerDto.Password = pwd;
            }

            CheckPassword(registerDto.Password);

            var resp = verifyCode.CheckCode(registerDto.Account, registerDto.VerifyCode);
            if (resp == 0)
            {
                return new ApiResult(AjaxCode.Fail, ServiceLocalizer["YB0210"].Value);
            }
            if (resp == -1)
            {
                return new ApiResult(AjaxCode.Fail, ServiceLocalizer["YB0211"].Value);
            }
            SysUser entity = null;
            if (RegChecker.IsEmail(registerDto.Email.ToLower()))
            {
                entity = SysUserRepository.Update(t => t.Email.ToLower() == registerDto.Email.ToLower(),
                    d =>
                    {
                        d.Password = registerDto.Password.GetMD5();
                        d.LastUpdatedDate = DateTime.Now;
                        d.IsPasswordNeedToChange = false;
                    }
                    );
            }
            else if (RegChecker.IsMobilePhone(registerDto.Account.ToLower()))
            {
                entity = SysUserRepository.Update(t => t.PhoneNumber.ToLower() == registerDto.Account.ToLower(), d =>
                {
                    d.Password = registerDto.Password.GetMD5();
                    d.LastUpdatedDate = DateTime.Now;
                    d.IsPasswordNeedToChange = false;
                });
            }
            var count = await UnitOfWork.SaveChangesAsync();
            return ApiResult.Success(ServiceLocalizer["YB0212"].Value).SetData(entity.CopyTo<SysUserListDto>());
        }

        public async Task<ApiResult> ResetPassWord(RegisterDto registerDto)
        {
            var resp = verifyCode.CheckCode(registerDto.Account, registerDto.VerifyCode);
            if (resp == 0)
            {
                return new ApiResult(AjaxCode.Fail, ServiceLocalizer["YB0210"].Value);
            }
            if (resp == -1)
            {
                return new ApiResult(AjaxCode.Fail, ServiceLocalizer["YB0211"].Value);
            }
            SysUser entity = null;
            if (RegChecker.IsEmail(registerDto.Email.ToLower()))
            {
                entity = SysUserRepository.Update(t => t.Email.ToLower() == registerDto.Email.ToLower(),
                    d =>
                    {
                        d.Password = registerDto.Password.GetMD5();
                        d.LastUpdatedDate = DateTime.Now;
                        d.IsPasswordNeedToChange = false;
                    });
            }
            else if (RegChecker.IsMobilePhone(registerDto.Email.ToLower()))
            {
                entity = SysUserRepository.Update(t => t.PhoneNumber.ToLower() == registerDto.Email.ToLower(), d =>
                {
                    d.Password = registerDto.Password.GetMD5();
                    d.LastUpdatedDate = DateTime.Now;
                    d.IsPasswordNeedToChange = false;
                });
            }
            else if (RegChecker.IsMobilePhone(registerDto.PhoneNumber.NullToString().ToLower()))
            {
                entity = SysUserRepository.Update(t => t.PhoneNumber.ToLower() == registerDto.PhoneNumber.ToLower(),
                    d =>
                {
                    d.Password = registerDto.Password.GetMD5();
                    d.LastUpdatedDate = DateTime.Now;
                    d.IsPasswordNeedToChange = false;
                });
            }
            var count = await UnitOfWork.SaveChangesAsync();
            return ApiResult.Success(ServiceLocalizer["YB0212"].Value).SetData(entity.CopyTo<SysUserListDto>());
        }

        public async Task<ApiResult> ResetPassWordFromApp(RegisterDto registerDto)
        {
            var resp = verifyCode.CheckCode(registerDto.Email, registerDto.VerifyCode);
            if (resp == 0)
            {
                return new ApiResult(AjaxCode.Fail, ServiceLocalizer["YB0210"].Value);
            }

            if (resp == -1)
            {
                return new ApiResult(AjaxCode.Fail, ServiceLocalizer["YB0211"].Value);
            }

            var entity = SysUserRepository.Update(t => t.Email.ToLower() == registerDto.Email.ToLower(),

                d =>
                {
                    d.Password = registerDto.Password.GetMD5();
                    d.LastUpdatedDate = DateTime.Now;
                });

            var count = await UnitOfWork.SaveChangesAsync();
            return ApiResult.Success(ServiceLocalizer["YB0212"].Value).SetData(entity);
        }

        /// <summary>
        /// 移动端用户修改密码接口
        /// </summary>
        /// <param name="registerDto"></param>
        /// <returns></returns>
        public async Task<ApiResult> ChangePasswordFromApp(RegisterDto registerDto)
        {
            var resp = verifyCode.CheckCode(registerDto.Email, registerDto.VerifyCode);
            if (resp == 0)
            {
                return new ApiResult(AjaxCode.Fail, ServiceLocalizer["YB0210"].Value);
            }

            if (resp == -1)
            {
                return new ApiResult(AjaxCode.Fail, ServiceLocalizer["YB0211"].Value);
            }

            var entity = SysUserRepository.Update(t => t.Email.ToLower() == registerDto.Email.ToLower(),

                d =>
                {
                    d.Password = registerDto.Password.GetMD5();
                    d.LastUpdatedDate = DateTime.Now;
                    d.IsPasswordNeedToChange = false;
                });

            var count = await UnitOfWork.SaveChangesAsync();
            return ApiResult.Success(ServiceLocalizer["YB0212"].Value).SetData(entity);
        }

        public async Task<ApiResult> ChangePassWord(ResetDto dto)
        {
            if (!string.IsNullOrWhiteSpace(dto.VerifyCode))
            {
                var verifyResult = verifyCode.CheckCode(dto.VerifyAccount, dto.VerifyCode);
                if (verifyResult == 0)
                    return new ApiResult(AjaxCode.Fail, ServiceLocalizer["YB0210"].Value);
                else if (verifyResult == -1)
                    return new ApiResult(AjaxCode.Fail, ServiceLocalizer["YB0211"].Value);
            }
            var userId = OperatorProvider.Get()?.YunUserGuid;
            if (userId.IsNull())
            {
                return new ApiResult(AjaxCode.Fail, ServiceLocalizer["YB0409"].Value);
            }
            var user = await SysUserRepository.GetByIdAsync(userId);
            try
            {
                RSACryptoService rsa = new RSACryptoService(RSACryptoService.DefaultPrivateKey, RSACryptoService.DefaultPublicKey);
                dto.OldPassword = rsa.Decrypt(dto.OldPassword);
                dto.NewPassword = rsa.Decrypt(dto.NewPassword);
            }
            catch
            {
                return new ApiResult(AjaxCode.Fail, ServiceLocalizer["YB0410"].Value);
            }

            if (user.IsNotNull() && user.Password != dto.OldPassword.Trim().GetMD5())
            {
                return new ApiResult(AjaxCode.Fail, ServiceLocalizer["YB0411"].Value);
            }

            if (user.Password == dto.NewPassword.Trim().GetMD5())
            {
                return new ApiResult(AjaxCode.Fail, ServiceLocalizer["YB0412"].Value);
            }
            user.Password = dto.NewPassword.Trim().GetMD5();
            user.IsPasswordNeedToChange = false;

            cached.Remove(OperatorProvider.Get().LogId);
            SysUserRepository.Update(user);
            var count = await UnitOfWork.SaveChangesAsync();
            return ApiResult.Success(ServiceLocalizer["YB0212"].Value).SetData(user);
        }

        public async Task<ApiPageResult> GetChildAccountPaged(SysUserPageDto pageDto)
        {
            var userId = OperatorProvider.Get()?.YunUserGuid;
            var userQuery = MsUserToUserRepository.GetAll().Where(t => t.YunUserGuidLeft == userId);

            pageDto.OrderBy = "CreatedDate Desc";

            var entities = await SysUserRepository.GetAll()
                .Join(userQuery, r => r.YunUserGuid, u => u.YunUserGuidRight, (r, u) => r)
                .WhereIf(!string.IsNullOrWhiteSpace(pageDto.Query), w => w.Email.ToLower().Contains(pageDto.Query.ToLower()) || w.PhoneNumber.Contains(pageDto.Query))
                .Where(p => p.IsDeleted == false)
                .ToPageList(pageDto);

            var result = pageDto.CopyTo<ApiPageResult>();
            result.PageData = entities;
            return result;
        }

        public async Task<ApiResult> DelChildAccount(Guid guid)
        {
            var userId = OperatorProvider.Get()?.YunUserGuid;

            await MsUserToUserRepository.DeleteAsync(t => t.YunUserGuidLeft == userId && t.YunUserGuidRight == guid);
            await SysUserRepository.DeleteAsync(t => t.YunUserGuid == guid);
            await UnitOfWork.SaveChangesAsync();

            return new ApiResult(AjaxCode.Success, ServiceLocalizer["YB0413"].Value);
        }

        public async Task<ApiResult> AddChildAccount(RegisterDto registerDto)
        {
            var operatorId = OperatorProvider.Get()?.YunUserGuid ?? Guid.Empty;
            var user = await SysUserRepository.FirstOrDefaultAsync(t => t.Email.ToLower().Trim() == registerDto.Email.ToLower().Trim() && t.IsDeleted == false);
            if (user.IsNotNull())
            {
                return new ApiResult(AjaxCode.Error, ServiceLocalizer["YB0414"].Value);
            }
            else
            {
                var userId = Guid.NewGuid();
                user = new SysUser
                {
                    YunUserGuid = userId,
                    Password = InitPwd.GetMD5(),
                    Status = EnumUserStatus.正常,
                    UserType = EnumUserType.子账号,
                    PhoneNumber = registerDto.PhoneNumber.NullToString().Trim(),
                    Email = registerDto.Email.ToLower().Trim(),
                    Name = registerDto.Account.Trim(),
                    IsLocked = EnumIsLocked.正常,
                    AccountNumber = registerDto.Email.ToLower().Trim(),
                    IsDeleted = false,
                    IsManualMeasureMan = registerDto.IsManualMeasureMan
                };
                SysUserRepository.Add(user);
            }
            MsUserToUserRepository.Add(new Core.Model.Ms.MsUserToUser { YunUserGuidLeft = operatorId, YunUserGuidRight = user.YunUserGuid });
            if (registerDto.ProjectGuids.IsNotEmpty())
            {
                registerDto.ProjectGuids.ForEach(t => MsUserToProjectRepository.Add(new Core.Model.Ms.MsUserToProject { YunUserGuid = user.YunUserGuid, YunProjectGuid = t, MsUserToProjectId = Guid.NewGuid() }));
            }

            await UnitOfWork.SaveChangesAsync();
            return new ApiResult(AjaxCode.Success, ServiceLocalizer["YB0415"].Value);
        }

        public async Task<ApiResult> UpdateChildAccount(RegisterDto registerDto)
        {
            var user = await SysUserRepository.FirstOrDefaultAsync(t => t.Email.ToLower().Trim() == registerDto.OldEmail.ToLower().Trim());
            if (user.IsNull())
            {
                return new ApiResult(AjaxCode.Error, ServiceLocalizer["YB0416"].Value);
            }
            else
            {
                if (registerDto.Email.ToLower().Trim() != registerDto.OldEmail.ToLower().Trim())//修改了邮箱账号
                {
                    var temp = await SysUserRepository.FirstOrDefaultAsync(t => t.Email.ToLower().Trim() == registerDto.Email.ToLower().Trim());
                    if (temp != null)
                    {
                        return new ApiResult(AjaxCode.Error, ServiceLocalizer["YB0414"].Value);
                    }
                    else
                    {
                        user.Email = registerDto.Email.ToLower().Trim();
                        user.Name = registerDto.Email.ToLower().Trim();
                        user.AccountNumber = registerDto.Email.ToLower().Trim();
                        user.IsManualMeasureMan = registerDto.IsManualMeasureMan ?? false;
                        SysUserRepository.Update(user);
                    }
                }
            }
            await MsUserToProjectRepository.DeleteAsync(t => t.YunUserGuid == user.YunUserGuid);
            if (registerDto.ProjectGuids.IsNotEmpty())
            {
                registerDto.ProjectGuids.ForEach(t => MsUserToProjectRepository.Add(new Core.Model.Ms.MsUserToProject { YunUserGuid = user.YunUserGuid, YunProjectGuid = t, MsUserToProjectId = Guid.NewGuid() }));
            }

            user.IsManualMeasureMan = registerDto.IsManualMeasureMan ?? false;
            SysUserRepository.Update(user);

            await UnitOfWork.SaveChangesAsync();
            return new ApiResult(AjaxCode.Success, ServiceLocalizer["ModifySuccess"].Value);
        }

        public async Task<ApiResult> GetDogUser(RegisterDto registerDto)
        {
            var sysUser = await SysUserRepository.GetDogUser(registerDto);
            return ApiResult.Success().SetData(sysUser);
        }

        #endregion 激活

        #region surface安装包

        public List<AppDto> GetSurfaceVerData()
        {
            List<AppDto> list = new List<AppDto>();
            var surfaceVerFile = Path.Combine(uploadFileOptions.ParentDir, uploadFileOptions.SurfacePackage, "surfaceVer.xml");

            if (File.Exists(surfaceVerFile))
            {
                XElement doc = XElement.Load(surfaceVerFile);

                IEnumerable<XElement> elements = from result in doc.Elements("app")
                                                 select result;
                foreach (XElement element in elements)
                {
                    AppDto appDto = new AppDto();
                    appDto.AppID = element.Attribute("AppID").Value;
                    int.TryParse(element.Attribute("Version").Value.NullToString(), out var version);
                    appDto.Version = version;
                    appDto.File = element.Attribute("File").Value;
                    appDto.SurfaceVersion = element.Attribute("SurfaceVersion").Value;
                    appDto.SurfaceNextVersion = element.Attribute("SurfaceNextVersion").Value;
                    list.Add(appDto);
                }
            }
            return list;
        }

        /// <summary>
        /// 获取SURFACE指定版本的更新包信息
        /// </summary>
        /// <param name="appDto"></param>
        /// <returns></returns>
        public async Task<ApiResult> GetSurfaceVersionInfo(AppDto appDto)
        {
            ApiResult apiResult = new ApiResult();

            #region 配置中的最大版本
            var curVers = GetSurfaceVerData();
            var maxNextVersion = curVers.Max(p => p.SurfaceNextVersion);
            Version serverVersion = null;
            Version.TryParse(maxNextVersion, out serverVersion);
            #endregion 配置中的最大版本

            #region 客户端版本
            Version clinetVersion = null;
            Version.TryParse(appDto.SurfaceVersion, out clinetVersion);
            #endregion 客户端版本

            AppDto appInfo = null;
            if (serverVersion > clinetVersion)
            {
                appInfo = curVers.Where(p => p.SurfaceNextVersion == maxNextVersion
                && p.AppID == appDto.AppID).FirstOrDefault();
            }
            if (appInfo == null)
            {
                return apiResult;
            }
            else
            {
                apiResult.Result = appInfo;
                apiResult.Code = AjaxCode.Success;
                return apiResult;
            }
        }

        #endregion surface安装包

        /// <summary>
        /// 系统支持的角色
        /// </summary>
        private static List<string> RoleList = new List<string>() { "公司管理员", "项目管理员", "测量管理员", "测量员" };

        /// <summary>
        /// 设备excel导入
        /// </summary>
        /// <param name="formFile"></param>
        /// <param name="IP"></param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        public async Task<bool> ImportExcelFile(IFormFile formFile, string IP)
        {
            #region 公司信息
            List<string> errorInfoList = new List<string>();
            List<int> errorIndexList = new List<int>();
            var orgPageResult = await SysOrgService.GetPage(new SysOrgPageDto() { PageSize = int.MaxValue });
            List<SysOrg> sysOrgs = orgPageResult.PageData as List<SysOrg>;
            if (sysOrgs == null || sysOrgs.Count == 0)
            {
                throw new OperationException(ServiceLocalizer["YB0417"].Value);
            }
            #endregion 公司信息

            #region 项目信息
            var projectPageResult = await ProjectService.GetList(new MsProjectCondition() { PageSize = int.MaxValue });
            List<MsProjectDto> msProjects = projectPageResult.PageData as List<MsProjectDto>;
            #endregion 项目信息

            string existedMsg = string.Empty;
            var excelDirectory = "";
            var FilePath = "";
            var errorString = "";
            var errorUserInfoList = new List<string>();
            try
            {
                if (formFile.Length == 0)
                    throw new OperationException(ServiceLocalizer["YB0007"].Value);

                using (var stream = formFile.OpenReadStream())
                {
                    excelDirectory = Path.Combine(uploadFileOptions.ParentDir, uploadFileOptions.DeviceExcelDir);
                    if (!Directory.Exists(excelDirectory)) Directory.CreateDirectory(excelDirectory);
                    FilePath = Path.Combine(excelDirectory, Guid.NewGuid() + Path.GetExtension(formFile.FileName));
                    using (FileStream fileStream = new FileStream(FilePath, FileMode.Create))
                    {
                        formFile.CopyTo(fileStream);
                    }
                }

                if (!File.Exists(FilePath))
                {
                    throw new OperationException(string.Format(ServiceLocalizer["YB0176"].Value, FilePath));
                }

                var fileInfo = new FileInfo(FilePath);
                if (!string.Equals(fileInfo.Extension, ".xlsx"))
                {
                    throw new OperationException(ServiceLocalizer["YB0458"].Value);
                }

                //List<string> listHeader = new List<string>() { "公司名称", "职位", "用户名称", "手机", "邮箱", "角色", "关联项目" };
                List<string> listHeader = new List<string>() { "用户名称", "职位", "手机", "邮箱", "角色", "关联项目" };

                //解析excel
                var excelTable = ExcelHelper.ReadToDataTable(FilePath);
                if (excelTable.Rows.Count == 0)
                {
                    throw new OperationException(ServiceLocalizer["YB0289"].Value);
                }

                foreach (DataColumn dc in excelTable.Columns)
                {
                    if (!listHeader.Contains(dc.ColumnName))
                    {
                        throw new OperationException(ServiceLocalizer["YB0418"].Value);
                    }
                }

                foreach (var header in listHeader)
                {
                    if (!excelTable.Columns.Contains(header))
                    {
                        throw new OperationException(ServiceLocalizer["YB0418"].Value);
                    }
                }

                int rowIndex = 0;
                var entityList = new List<SysUser>();
                string roleName = _tokenModel.RoleNameList;
                var curCom = sysOrgs.Where(p => p.Id == _tokenModel.CompanyGuid).FirstOrDefault();
                if (curCom == null)
                {
                    throw new OperationException(string.Format(ServiceLocalizer["YB0419"].Value, _tokenModel.CompanyGuid));
                }
                foreach (DataRow row in excelTable.Rows)
                {
                    var entity = new SysUser();
                    entity.ProjectIdList = new List<Guid>();
                    rowIndex++;
                    string preText = string.Format(ServiceLocalizer["YB0290"].Value, rowIndex);

                    if (string.IsNullOrEmpty(row["用户名称"].ToString()))
                    {
                        errorInfoList.Add(preText + ServiceLocalizer["YB0421"].Value);
                        errorIndexList.Add(rowIndex);
                        continue;
                    }
                    else
                    {
                        if (row["用户名称"].ToString().Length > 10)
                        {
                            errorInfoList.Add(preText + ServiceLocalizer["YB0422"].Value);
                            errorIndexList.Add(rowIndex);
                            continue;
                        }
                    }

                    if (string.IsNullOrEmpty(row["手机"].ToString().Trim()))
                    {
                        errorInfoList.Add(preText + ServiceLocalizer["YB0424"].Value);
                        errorIndexList.Add(rowIndex);
                        continue;
                    }
                    else
                    {
                        if (!RegChecker.IsMobilePhone(row["手机"].ToString()))
                        {
                            errorInfoList.Add(preText + ServiceLocalizer["YB0425"].Value);
                            errorIndexList.Add(rowIndex);
                            continue;
                        }
                    }

                    if (string.IsNullOrEmpty(row["邮箱"].ToString().Trim()))
                    {
                        errorInfoList.Add(preText + ServiceLocalizer["YB0364"].Value);
                        errorIndexList.Add(rowIndex);
                        continue;
                    }
                    else
                    {
                        if (!RegChecker.IsEmail(row["邮箱"].ToString()))
                        {
                            errorInfoList.Add(preText + ServiceLocalizer["YB0427"].Value);
                            errorIndexList.Add(rowIndex);
                            continue;
                        }

                        if (row["邮箱"].ToString().Length > 40)
                        {
                            errorInfoList.Add(preText + ServiceLocalizer["MailboxExceedLimit"].Value);
                            errorIndexList.Add(rowIndex);
                            continue;
                        }
                    }

                    if (string.IsNullOrEmpty(row["职位"].ToString().Trim()))
                    {
                        errorInfoList.Add(preText + ServiceLocalizer["YB0366"].Value);
                        errorIndexList.Add(rowIndex);
                        continue;
                    }
                    else
                    {
                        if (row["职位"].ToString().Length > 10)
                        {
                            errorInfoList.Add(preText + ServiceLocalizer["YB0429"].Value);
                            errorIndexList.Add(rowIndex);
                            continue;
                        }
                    }

                    string rowRole = row["角色"].ToString();
                    if (string.IsNullOrEmpty(row["角色"].ToString()))
                    {
                        errorInfoList.Add(preText + ServiceLocalizer["YB0367"].Value);
                        errorIndexList.Add(rowIndex);
                        continue;
                    }
                    else
                    {
                        string[] roles = row["角色"].ToString().Split(',', StringSplitOptions.RemoveEmptyEntries);
                        if (roles.Length > 1)
                        {
                            errorInfoList.Add(preText + ServiceLocalizer["YB0431"].Value);
                            errorIndexList.Add(rowIndex);
                            continue;
                        }
                        foreach (var role in roles)
                        {
                            if (!RoleList.Contains(role))
                            {
                                errorInfoList.Add(preText + string.Format(ServiceLocalizer["YB0432"].Value, role));
                                errorIndexList.Add(rowIndex);
                                continue;
                            }
                        }

                        if (_tokenModel.RoleNameList.Contains("公司管理员") == true)
                        {
                            if (rowRole.Contains("公司管理员"))
                            {
                                errorInfoList.Add(preText + $",{ServiceLocalizer["YB0369"].Value}");
                                errorIndexList.Add(rowIndex);
                            }
                        }
                        if (_tokenModel.RoleNameList.Contains("测量管理员") == true)
                        {
                            if (rowRole.Contains("公司管理员"))
                            {
                                errorInfoList.Add(preText + $",{ServiceLocalizer["YB0369"].Value}");
                                errorIndexList.Add(rowIndex);
                            }
                            if (rowRole.Contains("测量管理员"))
                            {
                                errorInfoList.Add(preText + string.Format(ServiceLocalizer["YB0372"].Value, roleName));
                                errorIndexList.Add(rowIndex);
                            }
                        }
                        if (_tokenModel.RoleNameList.Contains("项目管理员") == true)
                        {
                            if (rowRole.Contains("公司管理员"))
                            {
                                errorInfoList.Add(preText + $",{ServiceLocalizer["YB0369"].Value}");
                                errorIndexList.Add(rowIndex);
                            }
                            else if (rowRole.Contains("测量管理员"))
                            {
                                errorInfoList.Add(preText + $",{string.Format(ServiceLocalizer["YB0372"].Value, roleName)}");
                                errorIndexList.Add(rowIndex);
                            }
                            else if (rowRole.Contains("项目管理员"))
                            {
                                errorInfoList.Add(preText + $",{string.Format(ServiceLocalizer["YB0433"].Value, roleName)}");
                                errorIndexList.Add(rowIndex);
                            }
                            else if (rowRole.Contains("测量员"))
                            {
                                errorInfoList.Add(preText + $",{string.Format(ServiceLocalizer["YB0434"].Value, roleName)}");
                                errorIndexList.Add(rowIndex);
                            }
                        }
                        if (_tokenModel.RoleNameList.Contains("测量员") == true)
                        {
                            if (rowRole.Contains("公司管理员"))
                            {
                                errorInfoList.Add(preText + $",{ServiceLocalizer["YB0369"].Value}");
                                errorIndexList.Add(rowIndex);
                            }
                            else if (rowRole.Contains("测量管理员"))
                            {
                                errorInfoList.Add(preText + $",{string.Format(ServiceLocalizer["YB0372"].Value, roleName)}");
                                errorIndexList.Add(rowIndex);
                            }
                            else if (rowRole.Contains("项目管理员"))
                            {
                                errorInfoList.Add(preText + $",{string.Format(ServiceLocalizer["YB0433"].Value, roleName)}");
                                errorIndexList.Add(rowIndex);
                            }
                            else if (rowRole.Contains("测量员"))
                            {
                                errorInfoList.Add(preText + $",{string.Format(ServiceLocalizer["YB0434"].Value, roleName)}");
                                errorIndexList.Add(rowIndex);
                            }
                        }
                    }

                    if (!string.IsNullOrEmpty(row["关联项目"].ToString()))
                    {
                        if (msProjects == null || msProjects.Count == 0)
                        {
                            errorInfoList.Add(preText + string.Format(ServiceLocalizer["YB0436"].Value, row["关联项目"]));
                            errorIndexList.Add(rowIndex);
                            continue;
                        }
                        string[] projects = row["关联项目"].ToString().Split(',', StringSplitOptions.RemoveEmptyEntries);
                        foreach (var project in projects)
                        {
                            var prj = msProjects.Where(p => p.Name == project).FirstOrDefault();
                            if (prj == null)
                            {
                                errorInfoList.Add(preText + string.Format(ServiceLocalizer["YB0436"].Value, project));
                                errorIndexList.Add(rowIndex);
                                continue;
                            }
                            else
                            {
                                entity.ProjectIdList.Add(prj.ProjectId);
                            }
                        }
                    }

                    entity.YunUserGuid = Guid.NewGuid();
                    entity.Password = InitPwd.GetMD5();
                    entity.Name = row["用户名称"].ToString();
                    entity.Code = row["手机"].ToString();
                    entity.AccountNumber = row["手机"].ToString();
                    entity.PhoneNumber = row["手机"].ToString();
                    entity.Email = row["邮箱"].ToString();
                    entity.RoleNameList = row["角色"].ToString().Split(',').ToJsonStr();
                    entity.CompanyNo = curCom.Code.ToString();
                    entity.Company = curCom.Name.ToString();
                    entity.Department = curCom.Name.ToString();
                    entity.Position = row["职位"].ToString();
                    entity.UserType = EnumUserType.主账号;
                    entity.SysOrgId = curCom.Id.ToString();
                    entity.Status = (SysUser.EnumUserStatus)(Enum.Parse(typeof(SysUser.EnumUserStatus), "正常"));
                    entity.CreatedDate = DateTime.Now;
                    entity.LastUpdatedDate = DateTime.Now;
                    entity.LastUpdatedBy = OperatorProvider.Get()?.YunUserGuid ?? Guid.Empty;
                    entity.CreatedBy = OperatorProvider.Get()?.YunUserGuid ?? Guid.Empty;
                    entity.RowIndex = rowIndex;

                    //检查是否重复数据
                    var flag = await SysUserRepository.GetCheckUser(entity);
                    if (flag.Result == null)
                    {
                        entityList.Add(entity);
                    }
                    else
                    {
                        throw new OperationException(flag.Message);
                    }
                }

                if (entityList.Count > 0)
                {
                    if (errorIndexList.Count > 0)
                    {
                        string rowIndexMsg = string.Join(',', errorIndexList.ToArray());
                        string rowMsg = string.Join(";", errorInfoList.ToArray());
                        string msg = string.Format(ServiceLocalizer["YB0437"].Value, rowIndexMsg, rowMsg);
                        throw new OperationException(msg);
                    }

                    //检查Excel中的数据是否重复
                    for (int i = 0; i < entityList.Count; i++)
                    {
                        var t1 = entityList[i];
                        for (int j = i + 1; j < entityList.Count; j++)
                        {
                            var t2 = entityList[j];

                            if (t1.PhoneNumber == t2.PhoneNumber)
                            {
                                throw new OperationException(string.Format(ServiceLocalizer["YB0438"].Value, t1.RowIndex, t2.RowIndex));
                            }

                            if (t1.Email == t2.Email)
                            {
                                throw new OperationException(string.Format(ServiceLocalizer["YB0439"].Value, t1.RowIndex, t2.RowIndex));
                            }
                        }
                    }
                    #region

                    List<MsUserToProject> listMsUserPro = new List<MsUserToProject>();
                    foreach (var entity in entityList)
                    {
                        foreach (var prjId in entity.ProjectIdList)
                        {
                            MsUserToProject msUserToProjectDto = new MsUserToProject();
                            msUserToProjectDto.YunProjectGuid = prjId;
                            msUserToProjectDto.YunUserGuid = entity.YunUserGuid;
                            msUserToProjectDto.CreatedBy = OperatorProvider.Get()?.YunUserGuid ?? Guid.Empty;
                            msUserToProjectDto.CreatedDate = DateTime.Now;
                            msUserToProjectDto.MsUserToProjectId = Guid.NewGuid();
                            listMsUserPro.Add(msUserToProjectDto);
                        }
                    }

                    MsUserToProjectRepository.AddRange(listMsUserPro);

                    #endregion 用户

                    SysUserRepository.AddRange(entityList);

                    if (errorUserInfoList.Count() > 0)
                    {
                        errorString = ServiceLocalizer["YB0440"].Value + string.Join(';', errorUserInfoList.ToArray());
                        throw new OperationException(errorString);
                    }

                    if (await UnitOfWork.SaveChangesAsync() > 0)
                    {
                        //开始发送通知给批量导入的用户
                        foreach (var user in entityList)
                        {
                            //由于短信有限制，所以忽略错误，保证邮件可以发送
                            try
                            {
                                SendMessageToUser(user, InitPwd, IP);
                                await UserToProjectMessageService.AddUserSendMessage(IP, user.ProjectIdList, user.Name,
                                     user.PhoneNumber, user.YunUserGuid);
                            }
                            catch (Exception ex)
                            {
                                Logger.Error(ex.Message.ToString());
                            }
                        }

                        return true;
                    }
                }
                else
                {
                    if (errorIndexList.Count > 0)
                    {
                        string rowIndexMsg = string.Join(',', errorIndexList.ToArray());
                        string rowMsg = string.Join(";", errorInfoList.ToArray());
                        string msg = string.Format(ServiceLocalizer["YB0437"].Value, rowIndexMsg, rowMsg);
                        throw new OperationException(msg);

                        //throw new Exception("以下数据行存在错误，请修正后重新上传：" + string.Join(',', errorIndexList.ToArray()));
                    }

                    throw new OperationException(ServiceLocalizer["YB0323"].Value + existedMsg);
                }
            }
            finally
            {
                if (File.Exists(FilePath))
                {
                    File.Delete(FilePath);
                }
            }
            return false;
        }

        #endregion

        public async Task<ApiResult> GetDeviceAssign(Guid userId)
        {
            var token = OperatorProvider.Get();
            if (!token.IsCompanyAdmin)
                return ApiResult.Success();
            var device = await SysDeviceRepository.GetSysDeviceNoDelete(new SearcheParaSysDevicePage() { DeviceUserId = userId });

            var user = SysUserRepository.Where(u => u.YunUserGuid == userId).SingleOrDefault();

            if (device != null /*&& user != null && user.RoleNameList.Contains("测量管理员")*/)
            {
                return ApiResult.Success("OK").SetData(device.PageData);
            }
            return ApiResult.Success();
        }

        /// <summary>
        /// 更新用户状态：激活或禁用
        /// </summary>
        /// <param name="model"></param>
        /// <param name="opeId"></param>
        /// <returns></returns>
        public async Task UpdateUserStatus(SysUserDto model, Guid opeId)
        {
            if (model.UserId == Guid.Empty)
            {
                throw new OperationException("用户ID不能为空");
            }
            if ((int)model.Status != 0 && (int)model.Status != 1)
            {
                throw new OperationException("用户状态码不正确");
            }
            var userInfo = await SysUserRepository.GetByIdAsync(model.UserId);
            if (userInfo == null)
            {
                throw new OperationException("用户不存在");
            }
            if (userInfo.IsDeleted)
            {
                throw new OperationException("用户已删除");
            }
            CheckRight(model);
            userInfo.Status = model.Status;
            SysUserRepository.Update(userInfo);
            await UnitOfWork.SaveChangesAsync();
        }
    }
}